﻿// Copyright (c) .NET Foundation and contributors. All rights reserved.

// REF: https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Extensions/src/ProblemDetails.cs
namespace Asp.Versioning;

using Newtonsoft.Json;
using static Newtonsoft.Json.NullValueHandling;

/// <summary>
/// A machine-readable format for specifying errors in HTTP API responses based on https://tools.ietf.org/html/rfc7807.
/// </summary>
public class ProblemDetails
{
    [JsonExtensionData]
    private readonly IDictionary<string, object?> extensions;

    /// <summary>
    /// Initializes a new instance of the <see cref="ProblemDetails"/> class.
    /// </summary>
    public ProblemDetails() => extensions = new Dictionary<string, object?>( StringComparer.Ordinal );

    /// <summary>
    /// Initializes a new instance of the <see cref="ProblemDetails"/> class.
    /// </summary>
    /// <param name="extensions">A dictionary of additional extension data.</param>
    [JsonConstructor]
    public ProblemDetails( IDictionary<string, object?> extensions ) => this.extensions = extensions;

    /// <summary>
    /// Gets or sets a URI reference [RFC3986] that identifies the problem type. This specification encourages that, when
    /// dereferenced, it provide human-readable documentation for the problem type
    /// (e.g., using HTML [W3C.REC-html5-20141028]). When this member is not present, its value is assumed to be
    /// "about:blank".
    /// </summary>
    [JsonProperty( "type", NullValueHandling = Ignore )]
    public string? Type { get; set; }

    /// <summary>
    /// Gets or sets a short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence
    /// of the problem, except for purposes of localization(e.g., using proactive content negotiation;
    /// see[RFC7231], Section 3.4).
    /// </summary>
    [JsonProperty( "title", NullValueHandling = Ignore )]
    public string? Title { get; set; }

    /// <summary>
    /// Gets or sets the HTTP status code([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.
    /// </summary>
    [JsonProperty( "status", NullValueHandling = Ignore )]
    public int? Status { get; set; }

    /// <summary>
    /// Gets or sets a human-readable explanation specific to this occurrence of the problem.
    /// </summary>
    [JsonProperty( "detail", NullValueHandling = Ignore )]
    public string? Detail { get; set; }

    /// <summary>
    /// Gets or sets a URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced.
    /// </summary>
    [JsonProperty( "instance", NullValueHandling = Ignore )]
    public string? Instance { get; set; }

    /// <summary>
    /// Gets the <see cref="IDictionary{TKey, TValue}"/> for extension members.
    /// <para>
    /// Problem type definitions MAY extend the problem details object with additional members. Extension members appear in the same namespace as
    /// other members of a problem type.
    /// </para>
    /// </summary>
    /// <remarks>
    /// The round-tripping behavior for <see cref="Extensions"/> is determined by the implementation of the Input \ Output formatters.
    /// In particular, complex types or collection types may not round-trip to the original type when using the built-in JSON or XML formatters.
    /// </remarks>
    [JsonExtensionData]
    public IDictionary<string, object?> Extensions => extensions;
}